`include "common_header.verilog"

//  *************************************************************************
//  File : mld_rx_reorder_40g_64b.vhd
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2008 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Denis Poverennyy
//  info@morethanip.com
//  *************************************************************************
//  Description : 40G PCS Multi-Lane Distribution (Rx) over 4 lanes
//                Note: zero latency, does not use any output registers.
//  Version     : $Id: mld_rx_reorder_40g_64b.v,v 1.3 2014/10/09 14:58:07 dk Exp $
//  *************************************************************************

module mld_rx_reorder_40g_64b (

        reset_rxclk,
        rxclk,
        desk_buf_0_data,
        desk_buf_1_data,
        desk_buf_2_data,
        desk_buf_3_data,
        vl_map_0,
        vl_map_1,
        vl_map_2,
        vl_map_3,
        mld_data_vld_adv,
        mld_data_vld,
        data_vld,
        align_done,
        loopback_ena,
        cgmii_txclk_ena,
        data_val,
        data_type_out,
        data_out,
        lane_map);

input           reset_rxclk;            //  async active high reset
input           rxclk;            //  > 
input   [65:0]  desk_buf_0_data;        //  buffer 0 data output
input   [65:0]  desk_buf_1_data;        //  buffer 1 data output
input   [65:0]  desk_buf_2_data;        //  buffer 2 data output
input   [65:0]  desk_buf_3_data;        //  buffer 3 data output
input   [3:0]   vl_map_0;               //  Virtual Lane Mapping
input   [3:0]   vl_map_1; 
input   [3:0]   vl_map_2; 
input   [3:0]   vl_map_3; 
input           mld_data_vld_adv;       //  data available, one cycle in advance
input           mld_data_vld;           //  data available in the input register
input           data_vld;               //  all data valid including markers
input           align_done;             //  used to generate clock enables when 
input           loopback_ena;           //  XLGMII loopback enable
input           cgmii_txclk_ena;        //  XLGMII transmit clock enable
output          data_val;               //  data valid
output  [1:0]   data_type_out;          //  data 0 type (Data/Control)
output  [63:0]   data_out;              //  data 0 output


output   [7:0] lane_map; 

reg             data_val; 
reg     [1:0] data_type_out; 
reg     [63:0] data_out; 


reg     [7:0] lane_map; 
wire    [3:0] vl_0_det; //  Virtual Lane <x> detected
wire    [3:0] vl_1_det; 
wire    [3:0] vl_2_det; 
wire    [3:0] vl_3_det; 
reg     [3:0] vl_0_sel; 
reg     [3:0] vl_1_sel; 
reg     [3:0] vl_2_sel; 
reg     [3:0] vl_3_sel; 
reg     [1:0] vl_0_selb; 
reg     [1:0] vl_1_selb; 
reg     [1:0] vl_2_selb; 
reg     [1:0] vl_3_selb; 
wire    [65:0] vl_0; //  Virtual Lane data
wire    [65:0] vl_1; 
wire    [65:0] vl_2; 
wire    [65:0] vl_3; 
reg     loopback_ena_s; 
reg     mld_data_vld_r;
reg     mld_data_vld_r2;


// convert 4-bit one-hot array to a 2-bit selector. 
function [1:0] VL_SEL_TO_BIN;
input [3:0] vl_sel;
begin
        // 0000 => 00;
        // 0001 => 00;
        // 0010 => 01;
        // 0100 => 10;
        // 1000 => 11;
        
        VL_SEL_TO_BIN[0] = vl_sel[1] | vl_sel[3];
        VL_SEL_TO_BIN[1] = vl_sel[2] | vl_sel[3];
        
end
endfunction

function [65:0] VL_DATA_REORDER_BIN;
input   [65:0] data_0; 
input   [65:0] data_1; 
input   [65:0] data_2; 
input   [65:0] data_3; 
input   [1:0] vl_sel; 
begin

   case (vl_sel)
      2'b 00: VL_DATA_REORDER_BIN = data_0;
      2'b 01: VL_DATA_REORDER_BIN = data_1;
      2'b 10: VL_DATA_REORDER_BIN = data_2;
      2'b 11: VL_DATA_REORDER_BIN = data_3;
      default:  VL_DATA_REORDER_BIN = data_3;
   endcase

end
endfunction

//  One hot coding vector to detect on which physical lane 
//  detected particular virtual lane

assign vl_0_det = {vl_map_3[0], vl_map_2[0], vl_map_1[0], vl_map_0[0]}; 
assign vl_1_det = {vl_map_3[1], vl_map_2[1], vl_map_1[1], vl_map_0[1]}; 
assign vl_2_det = {vl_map_3[2], vl_map_2[2], vl_map_1[2], vl_map_0[2]}; 
assign vl_3_det = {vl_map_3[3], vl_map_2[3], vl_map_1[3], vl_map_0[3]}; 

always @(posedge rxclk or posedge reset_rxclk)
   begin : process_1
   if (reset_rxclk == 1'b 1)
      begin
      vl_0_sel <= {4{1'b 0}};	
      vl_1_sel <= {4{1'b 0}};	
      vl_2_sel <= {4{1'b 0}};	
      vl_3_sel <= {4{1'b 0}};	
      vl_0_selb<= {2{1'b 0}};	
      vl_1_selb<= {2{1'b 0}};	
      vl_2_selb<= {2{1'b 0}};	
      vl_3_selb<= {2{1'b 0}};	
      end
   else
      begin

        // get one-hot indicator
        
        vl_0_sel <= vl_0_det;	
        vl_1_sel <= vl_1_det;	
        vl_2_sel <= vl_2_det;	
        vl_3_sel <= vl_3_det;	

        // convert into 2-bit binary for controlling 4:1 mux

        vl_0_selb <= VL_SEL_TO_BIN( vl_0_sel );
        vl_1_selb <= VL_SEL_TO_BIN( vl_1_sel );
        vl_2_selb <= VL_SEL_TO_BIN( vl_2_sel );
        vl_3_selb <= VL_SEL_TO_BIN( vl_3_sel );
        
      end
   end

 

//  remapping depending on actual virtual lanes distribution
//  over phisical ones

assign vl_0 = VL_DATA_REORDER_BIN(desk_buf_0_data, desk_buf_1_data, desk_buf_2_data, desk_buf_3_data, vl_0_selb); 
assign vl_1 = VL_DATA_REORDER_BIN(desk_buf_0_data, desk_buf_1_data, desk_buf_2_data, desk_buf_3_data, vl_1_selb); 
assign vl_2 = VL_DATA_REORDER_BIN(desk_buf_0_data, desk_buf_1_data, desk_buf_2_data, desk_buf_3_data, vl_2_selb); 
assign vl_3 = VL_DATA_REORDER_BIN(desk_buf_0_data, desk_buf_1_data, desk_buf_2_data, desk_buf_3_data, vl_3_selb);


//  output data valid
always @(posedge rxclk or posedge reset_rxclk)
begin
        if (reset_rxclk == 1'b 1)
        begin
                data_val        <= 1'b 0;	
                loopback_ena_s  <= 1'b 0;
                mld_data_vld_r  <= 1'b0;	
                mld_data_vld_r2 <= 1'b0;
        end
        else
        begin
                mld_data_vld_r  <= mld_data_vld;	
                mld_data_vld_r2 <= mld_data_vld_r;
                loopback_ena_s <= loopback_ena;	
                if (loopback_ena_s == 1'b 1)
                begin
                        data_val <= cgmii_txclk_ena;	
                end
                else
                begin
                        data_val <= mld_data_vld_adv | mld_data_vld | mld_data_vld_r | mld_data_vld_r2 | ~align_done;                        
                end
        end
end



always @(*)
begin
        if (mld_data_vld == 1'b1)
        begin
                data_type_out = vl_0[1:0]; 
                data_out      = vl_0[65:2];
        end
        else if (mld_data_vld_r == 1'b1)
        begin
                data_type_out = vl_1[1:0]; 
                data_out      = vl_1[65:2];
        end
        else if (mld_data_vld_r2 == 1'b1)
        begin
                data_type_out = vl_2[1:0]; 
                data_out      = vl_2[65:2];
        end
        else //if (mld_data_vld_r3 == 1'b1)
        begin
                data_type_out = vl_3[1:0]; 
                data_out      = vl_3[65:2];
        end

end





//  Mapping between physical and virtual lanes
//  only for register

always @(posedge rxclk or posedge reset_rxclk)
   begin : process_6
   if (reset_rxclk == 1'b 1)
      begin
      lane_map <= {8{1'b 0}};	
      end
   else
      begin
      lane_map <= {vl_3_selb, vl_2_selb, vl_1_selb, vl_0_selb};	
      end
   end





endmodule // module mld_rx_reorder_40g_64b